﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;

namespace OpiConsole
{
    /// <summary>
    /// The type of CVar that is being stored
    /// </summary>
    public enum CVarType
    {
        INT,
        FLOAT,
        VECTOR2,
        VECTOR3,
        COLOR,
        RECTANGLE,
        BOOL,
        STRING
    }

    public abstract class CVar
    {
        protected static Game m_pGame;

        private CVarType m_eCVarType;
        private UsageLevel m_eUsageLevel;
        private bool m_bSaveToFile;
        private String m_sName;
        private String m_sCVarVal;
        private String m_sDefaultVal;

        public CVarType CVarType
        {
            get { return m_eCVarType; }
        }

        public UsageLevel UsageLevel
        {
            get { return m_eUsageLevel; }
        }

        public bool SaveToFile
        {
            get { return m_bSaveToFile; }
        }

        public String Name
        {
            get { return m_sName; }
        }

        public String DefaultValue
        {
            get { return m_sDefaultVal; }
        }

        /// <summary>
        /// Initialising CVar uses this to set the static pointer to the game manager.
        /// </summary>
        /// <param name="gameManager"></param>
        public CVar(Game game)
        {
            m_pGame = game;
        }

        /// <summary>
        /// The default constructor for all CVars to be added to the CVarManager
        /// </summary>
        /// <param name="name"></param>
        /// <param name="defaultData"></param>
        /// <param name="cvarType"></param>
        /// <param name="cvarLevel"></param>
        /// <param name="save">Save this CVar to the Config?</param>
        public CVar(String name, String defaultData, CVarType cvarType, UsageLevel usageLevel, bool save)
        {
            m_sName = name;
            m_sDefaultVal = defaultData;
            m_eCVarType = cvarType;
            m_eUsageLevel = usageLevel;
            m_bSaveToFile = save;
        }

        public abstract bool Invoke(List<string> args);

        public String getUsage()
        {
            switch (m_eCVarType)
            {
                case CVarType.BOOL:
                    return "<i>";
                case CVarType.COLOR:
                    return "<r> <g> <b> <a>";
                case CVarType.FLOAT:
                    return "<i>";
                case CVarType.INT:
                    return "<i>";
                case CVarType.STRING:
                    return "<string>";
                case CVarType.VECTOR2:
                    return "<x> <y>";
                case CVarType.VECTOR3:
                    return "<x> <y> <z>";
                case CVarType.RECTANGLE:
                    return "<x> <y> <w> <h>";
                default:
                    return "<i>";
            }
        }

        public override String ToString()
        {
            if (m_sCVarVal != null)
                return m_sCVarVal;

            return m_sDefaultVal;
        }

        public int toInt()
        {
            if (m_sCVarVal != null && m_sCVarVal.Length > 0)
                return Parser.toInt(m_sCVarVal);

            else
                return Parser.toInt(m_sDefaultVal);
        }

        public float toFloat()
        {
            if (m_sCVarVal.Length > 0)
                return Parser.toFloat(m_sCVarVal);

            else
                return Parser.toFloat(m_sDefaultVal);
        }

        public Color toColor()
        {
            if (m_sCVarVal.Length > 0)
                return Parser.toColor(m_sCVarVal);
            else
                return Parser.toColor(m_sDefaultVal);
        }

        public Vector2 toVector2()
        {
            if (m_sCVarVal.Length > 0)
                return Parser.toVector2(m_sCVarVal);
            else
                return Parser.toVector2(m_sDefaultVal);
        }

        public Vector3 toVector3()
        {
            if (m_sCVarVal.Length > 0)
                return Parser.toVector3(m_sCVarVal);
            else
                return Parser.toVector3(m_sDefaultVal);
        }

        public bool toBool()
        {
            if (m_sCVarVal != null && m_sCVarVal.Length > 0)
                return Parser.toBool(m_sCVarVal);

            else
                return Parser.toBool(m_sDefaultVal);
        }

        public char toChar()
        { 
            //TODO: Check this works
            if (m_sCVarVal.Length > 0)
                return Parser.toChar(m_sCVarVal);
            else
                return Parser.toChar(m_sDefaultVal);

        }

        public Keys toKey()
        {
            //Todo
            return Keys.None;
        }

        public bool setValue(List<String> args)
        {
            m_sCVarVal = "";

            if (!argsValid(args))
                return false;

            foreach (String str in args)
                m_sCVarVal += str;

            m_sCVarVal.Trim();

            return true;
        }

        /// <summary>
        /// Checks the input args to make sure they are valid
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        public bool argsValid(List<String> args)
        {
            //Temp Variables
            switch (m_eCVarType)
            {
                case CVarType.BOOL:
                    try
                    {
                        if (args.Count == 1 && bool.Parse(args[0]))
                            return true;
                        break;
                    }
                    catch (System.FormatException)
                    {
                        break;
                    }

                case CVarType.COLOR:
                    if (args.Count > 0 && args.Count <= 3)
                    {
                        foreach (String str in args)
                        {
                            try
                            {
                               int.Parse(str);
                            }
                            catch (System.FormatException)
                            {
                                break;
                            }
                        }

                        return true;
                    }
                    break;
                case CVarType.FLOAT:
                    try
                    {
                        if (args.Count == 1)
                            float.Parse(args[0]);
                    }
                    catch (System.FormatException)
                    {
                        break;
                    }
                    return true;

                case CVarType.INT:
                    try
                    {
                        if (args.Count == 1)
                            int.Parse(args[0]);
                    }
                    catch (System.FormatException)
                    {
                        break;
                    }
                    return true;

                case CVarType.STRING:
                    if (args.Count > 0)
                        return true;
                    break;

                case CVarType.VECTOR2:
                    if (args.Count > 0 && args.Count <= 2)
                    {
                        foreach (String str in args)
                        {
                            try
                            {
                                if (args.Count == 1)
                                    float.Parse(str);
                            }
                            catch (System.FormatException)
                            {
                                break;
                            }
                        }
                        return true;
                    }
                    break;

                case CVarType.VECTOR3:
                    if (args.Count > 0 && args.Count <= 3)
                    {
                        foreach (String str in args)
                        {
                            try
                            {
                                if (args.Count == 1)
                                    float.Parse(str);
                            }
                            catch (System.FormatException)
                            {
                                break;
                            }
                        }
                        return true;
                    }
                    break;

                case CVarType.RECTANGLE:
                    if (args.Count > 0 && args.Count <= 4)
                    {
                        foreach (String str in args)
                        {
                            try
                            {
                                if (args.Count == 1)
                                    int.Parse(str);
                            }
                            catch (System.FormatException)
                            {
                                break;
                            }
                        }
                        return true;
                    }
                    break;
            }

            return false;
        }
    }

    #region Default_CVars

    public class CVar_Init : CVar
    {
        public CVar_Init(Game game)
            : base(game)
        {
        }

        public override bool Invoke(List<string> args)
        {
            return true;
        }
    }

    #endregion
}
